<?php
error_reporting(E_ALL);
class SpawFm
{
    public $thumbnails_enabled = false;
    public $current_dir = false;
    public $current_dir_data = false;
    public $current_type = false;
    public $image_ext = array('.gif', '.png', '.jpg', '.jpeg');
    public $error_msg = false;

	function SpawFm()
	{
	}


	public function normalizeDir($dir, $stripslashes = false, $noleadslash = false)
	{
		if (!strlen($dir)) {
			return false;
		}
		$dir = str_replace('\\', '/', $dir);
		if (!$noleadslash and !preg_match('#[a-z]+://#i', $dir)) {
			$dir = preg_replace('|^/*(.*)|', '/$1', $dir);
		}
		$dir = $this->addTrailingSlash($dir);
		if ($stripslashes) {
			return SpawVars::stripSlashes($dir);
		}
		return $dir;
	}

    public function addTrailingSlash($dir)
	{
		return preg_replace('|/*$|', '', $dir) . '/';
	}


    public function getFileIcon($filename)
	{
		$icons = $this->getFileIconsDefinition($filename);
		return $icons['icon'];
	}

    public function getFileIconBig($filename)
	{
		$icons = $this->getFileIconsDefinition($filename);
		return $icons['icon_big'];
	}

    public function getFileIconsDefinition($filename)
	{
		global $config;
		static $spawfm_ftypes_icons;
		$icons = false;
		$ext = $this->getFileExtension($filename);
		if (!isset($spawfm_ftypes_icons[$ext])) {
			// search for icon definition for this extension
			$icons_def = $config->getConfigValue('PG_SPAWFM_FILETYPES_ICONS');
			foreach ($icons_def as $definition) {
				if (in_array($ext, $definition['extensions'])) {
					$icons = array(
						'icon'     => $definition['icon'],
						'icon_big' => $definition['icon_big'],
					);
					break;
				}
			}

			// set default icon if definition not found
			if (!$icons) {
				$icons = $config->getConfigValue('PG_SPAWFM_FILETYPES_ICON_DEFAULT');
			}
			$spawfm_ftypes_icons[$ext] = $icons;
		} else {
			$icons = $spawfm_ftypes_icons[$ext];
		}
		return $icons;
	}

    public function getFileThumbnail($filename)
	{
		$icons = $this->getFileIconsDefinition($filename);
		return '../plugins/spawfm/img/' . $icons['icon_big'];
	}

    function getFileSize($file)
	{
		$fsize = @filesize($this->getCurrentFsDir() . $file);
		if (!$fsize) {
			$fsize = 0;
		}
		return $fsize;
	}

    function getFileDate($file)
	{
		$fdate = @filemtime($this->getCurrentFsDir() . $file);
		if (!$fdate) {
			$fdate = 0;
		}
		return $fdate;
	}

    function isImage($file)
	{
		$ext = $this->getFileExtension($file);
		if (in_array($ext, $this->imagescapeHtmle_ext)) {
			return true;
		}
		return false;
	}

    public function isThumbailsModePossible($dir_path)
	{
		// check required system tools for image resizing
		// check if current directory is writable
		return true;
	}

	function getCurrentDir()
	{
		return !empty($this->current_dir_data['dir']) ? $this->current_dir_data['dir'] : false;
	}

	function getCurrentFsDir()
	{
		return !empty($this->current_dir_data['fsdir']) ? $this->current_dir_data['fsdir'] : false;
	}

	function setCurrentDirData($dir_data)
	{
		$this->current_dir_data = $dir_data;
	}

	function getCurrentDirData()
	{
		return $this->current_dir_data;
	}

	function unsetCurrentDirData()
	{
		$this->current_dir_data = false;
	}

	function getCurrentDirSetting($name)
	{
		$data = $this->getCurrentDirData();
		if (isset($data['params'][$name])) {
			return $data['params'][$name];
		}
		return false;
	}

	function setCurrentType($type)
	{
		$this->current_type = $type;
	}

	function getCurrentType()
	{
		return $this->current_type;
	}

	// returns allowed extensions for selected directory and type
	function getAllowedExtensions()
	{
		global $config;
		$allowed_ext = array();
		if (!$this->getCurrentDir() or !$curr_dir_data = $this->getCurrentDirData()) {
			return $allowed_ext;
		}

		$filetypes = $config->getConfigValue('PG_SPAWFM_FILETYPES');

		if ($curr_type = $this->getCurrentType()) {
			$allowed_ext = $filetypes[$curr_type];
		} elseif (!empty($curr_dir_data['params']['allowed_filetypes'])) {
			if (!is_array($curr_dir_data['params']['allowed_filetypes'])) {
				$curr_dir_data['params']['allowed_filetypes'] = array($curr_dir_data['params']['allowed_filetypes']);
			}
			if (sizeof($curr_dir_data['params']['allowed_filetypes'])) {
				foreach ($curr_dir_data['params']['allowed_filetypes'] as $ftype) {
					if (strlen($ftype) and $ftype{0} == '.') { // extension specified
						$allowed_ext[] = $ftype;
					} elseif (isset($filetypes[$ftype])) { // filetype group specified
						$allowed_ext = array_merge($allowed_ext, $filetypes[$ftype]);
					}
				}
			}
		}
		return $allowed_ext;
	}

	// returns list of files in current directory
	function getFilesList()
	{
		global $lang;
		$files = array();

		if (!$this->getCurrentFsDir()) {
			return $files;
		}

		$allowed_ext = $this->getAllowedExtensions();
		if ($dh = @opendir($this->getCurrentFsDir())) {
			while (false !== ($file = readdir($dh))) {
				if (!is_dir($this->getCurrentFsDir() . $file)) {
					$ext = $this->getFileExtension($file);
					if (in_array('.*', $allowed_ext) or in_array($ext, $allowed_ext)) {
						$files[] = $file;
					}
				}
			}
			closedir($dh);
		} else {
			return false;
		}

		// reorder files by title
		natcasesort($files);

		// load files' details
		foreach ($files as $key => $file) {
			$ext = $this->getFileExtension($file);
			if (!strlen($fdescr = $lang->m($ext, 'filetypes'))) {
				$fdescr = strtoupper(substr($ext, 1)) . ' ' .
					$lang->m('filetype_suffix', 'file_details');
			}
			// additional info
			if ($imgsize = @getimagesize($this->getCurrentFsDir() . $file)) {
				$other = $lang->m('img_dimensions', 'file_details') . ': ' . $imgsize[0] . 'x' . $imgsize[1];
			} else {
				$other = '';
			}

			// get thumbail
			// TO DO

			$files[$key] = array(
				'type'     => 'F',
				'name'     => $file,
				'size'     => $this->getFileSize($file),
				'date'     => $this->getFileDate($file),
				'fdescr'   => $fdescr,
				'icon'     => '../plugins/spawfm/img/' . $this->getFileIcon($file),
				'icon_big' => '../plugins/spawfm/img/' . $this->getFileIconBig($file),
				'thumb'    => $this->getFileThumbnail($file),
				'other'    => $other
			);
		}

		return $files;
	}

	// returns list of files in current directory
	function getDirectoriesList()
	{
		global $lang, $config;
		$directories = array();

		if (!$this->getCurrentFsDir()) {
			return $directories;
		}

		if ($dh = @opendir($this->getCurrentFsDir())) {
			while (false !== ($file = readdir($dh))) {
				if (is_dir($this->getCurrentFsDir() . $file) and $file{0} != '.') {
					$directories[] = $file;
				}
			}
			closedir($dh);
		} else {
			return false;
		}

		// sort
		natcasesort($directories);

		// load details
		foreach ($directories as $key => $file) {
			$directories[$key] = array(
				'name'     => $file,
				'date'     => $this->getFileDate($file),
				'size'     => $this->getFileSize($file),
				'descr'    => $lang->m('file_folder', 'file_details'),
				'icon'     => '../plugins/spawfm/img/' . $config->getConfigValueElement('PG_SPAWFM_FILETYPES_ICON_FOLDER', 'icon'),
				'icon_big' => '../plugins/spawfm/img/' . $config->getConfigValueElement('PG_SPAWFM_FILETYPES_ICON_FOLDER', 'icon_big'),
				'thumb'    => $this->getFileThumbnail($file),
				'other'    => ''
			);
		}

		return $directories;
	}

	function setThumbnailsEnabled($status = false)
	{
		$this->thumbnails_enabled = $status;
	}

	function getThumbnailsEnabled()
	{
		return $this->thumbnails_enabled;
	}

	// static helper methods
	public function getFileExtension($filename)
	{
		return strtolower(strrchr($filename, '.'));
	}

	// adds slashes before single quotes
	public function escJsStr($str)
	{
		return addcslashes($str, '\'');
	}

	// strip leading slash
	function stripLeadSlash($dir)
	{
		if (strlen($dir) and ($dir{0} == '/' or $dir{0} == '\\')) {
			return substr($dir, 1);
		}
		return $dir;
	}

	// escape HTML special chars
	public function escapeHtml($str)
	{
		return str_replace(
			array('<', '>', '"'),
			array('&lt;', '&gt;', '&quot;'),
			$str
		);
	}

	function error()
	{
		return false !== $this->getError();
	}

	function getError()
	{
		return $this->error_msg;
	}

	function setError($msg)
	{
		$this->error_msg = $msg;
	}

	function deleteFile($del_file)
	{
		global $lang;

		// filter file/dir name
		$del_file = basename($del_file);

		if (file_exists($this->getCurrentFsDir() . $del_file)) {
			if (is_dir($this->getCurrentFsDir() . $del_file)) {
				if (!$this->getCurrentDirSetting('recursive') or
					!$this->getCurrentDirSetting('allow_modify_subdirectories')
				) {
					$this->setError($lang->m('error_delete_subdirectories_forbidden', 'spawfm'));
				} else {
					// check if directory is empty
					$empty = true;
					if ($dh = opendir($this->getCurrentFsDir() . $del_file)) {
						while (($file = readdir($dh)) !== false) {
							if ($file != '.' and $file != '..') {
								$empty = false;
								break;
							}
						}
						closedir($dh);
					}

					if (!$empty) {
						$this->setError($lang->m('error_delete_subdirectories_not_empty', 'spawfm'));
					} elseif (!@rmdir($this->getCurrentFsDir() . $del_file)) {
						$this->setError($lang->m('error_delete_subdirectories_failed', 'spawfm'));
					}
				}
			} else {
				if (!$this->getCurrentDirSetting('allow_modify')) {
					$this->setError($lang->m('error_delete_forbidden', 'spawfm'));
				} elseif (!@unlink($this->getCurrentFsDir() . $del_file)) {
					$this->setError($lang->m('error_delete_failed', 'spawfm'));
				}
			}
		}

		return !$this->error();
	}

	function renameFile($ren_old_name, $ren_new_name)
	{
		global $lang;

		// cleanup/filter file/directory names
		$ren_old_name = basename($ren_old_name);
		$ren_new_name = basename(trim($ren_new_name));

		// check if file/directory can be renamed
		if (!file_exists($this->getCurrentFsDir() . $ren_old_name)) {
			$this->setError($lang->m('error_rename_file_missing', 'spawfm'));
		} elseif (is_dir($this->getCurrentFsDir() . $ren_old_name) and
			!$this->getCurrentDirSetting('allow_modify_subdirectories')
		) {
			$this->setError($lang->m('error_rename_directories_forbidden', 'spawfm'));
		} elseif (!is_dir($this->getCurrentFsDir() . $ren_old_name) and
			!$this->getCurrentDirSetting('allow_modify')
		) {
			$this->setError($lang->m('error_rename_forbidden', 'spawfm'));
		} elseif (file_exists($this->getCurrentFsDir() . $ren_new_name)) {
			$this->setError(str_replace('[*FILE*]', $ren_new_name, $lang->m('error_rename_file_exists', 'spawfm')));
		} else {
			// check if filetype doesn't change
			if ($this->getFileExtension($ren_old_name) != $this->getFileExtension($ren_new_name)) {
				$this->setError($lang->m('error_rename_extension_changed', 'spawfm'));
				// check if new file name is secure (for files only)
			} elseif (!is_dir($this->getCurrentFsDir() . $ren_old_name) and !$this->isSecureFile($ren_new_name)) {
				$this->setError($lang->m('error_bad_filetype', 'spawfm'));
			} elseif (!@rename($this->getCurrentFsDir() . $ren_old_name, $this->getCurrentFsDir() . $ren_new_name)) {
				$this->setError($lang->m('error_rename_failed', 'spawfm'));
			}
		}

		return !$this->error();
	}

	function createDirectory($dir_name)
	{
		global $lang;

		if ($this->getCurrentDirSetting('recursive') and
			$this->getCurrentDirSetting('allow_create_subdirectories')
		) {
			// filter dir name
			$dir_name = trim(basename($dir_name));

			if (preg_match('#[:<>|?*"/\\\\]+#', $dir_name)) {
				$this->setError($lang->m('error_create_directories_name_invalid', 'spawfm'));
			} // check if name is not used already
			elseif (file_exists($this->getCurrentFsDir() . $dir_name)) {
				$this->setError($lang->m('error_create_directories_name_used', 'spawfm'));
			} else {
				// chmod created directory if specified
				if (strlen($this->getCurrentDirSetting('chmod_to'))) {
					$res = @mkdir($this->getCurrentFsDir() . $dir_name, $this->getCurrentDirSetting('chmod_to'));
				} else {
					$res = @mkdir($this->getCurrentFsDir() . $dir_name);
				}
				if (!$res) {
					$this->setError($lang->m('error_create_directories_failed', 'spawfm'));
				}
			}
		} else {
			$this->setError($lang->m('error_create_directories_forbidden', 'spawfm'));
		}

		return !$this->error();
	}

	function uploadFile($uplfile)
	{
		global $lang;

		// check if upload is allowed
		if (!$this->getCurrentDirSetting('allow_upload')) {
			$this->setError($lang->m('error_upload_forbidden', 'spawfm'));
		} else {
			if (is_uploaded_file($uplfile['tmp_name'])) {
				// check filetype
				$ext = $this->getFileExtension($uplfile['name']);
				$allowed_ext = $this->getAllowedExtensions();
				if ((in_array('.*', $allowed_ext) or in_array($ext, $allowed_ext)) and $this->isSecureFile($uplfile['name'])) {
					// check filesize
					if (!$this->getCurrentDirSetting('max_upload_filesize') or
						$uplfile['size'] <= $this->getCurrentDirSetting('max_upload_filesize')
					) {
						$ok = true;
						$err = array();
						/*
						  check image dimensions: try to read image dimensions (this step is
						  omitted if getimagesize() does not recognize file as image or fails
						  to read it's dimensions
						*/
						if (($this->getCurrentDirSetting('max_img_width') or
							$this->getCurrentDirSetting('max_img_height')) and
							$imgsize = @getimagesize($uplfile['tmp_name'])
						) {
							// check if dimensions not too big if specified
							if ($this->getCurrentDirSetting('max_img_width') and
								$imgsize[0] > $this->getCurrentDirSetting('max_img_width')
							) {
								$ok = false;
								$err[] = str_replace('[*MAXWIDTH*]', $this->getCurrentDirSetting('max_img_width'), $lang->m('error_img_width_max', 'spawfm'));
							}
							if ($this->getCurrentDirSetting('max_img_height') and
								$imgsize[1] > $this->getCurrentDirSetting('max_img_height')
							) {
								$ok = false;
								$err[] = str_replace('[*MAXHEIGHT*]', $this->getCurrentDirSetting('max_img_height'), $lang->m('error_img_height_max', 'spawfm'));
							}
						}
						if (!$ok) {
							$this->setError(implode('<br />', $err));
						} else {
							// proceed saving uploaded file
							//---------Преобразуем в латиницу
							$filename = convert_cyr_string($uplfile['name'], 'w', 'k');
							for ($i = 0; $i < strlen($filename); $i++) {
								$filename{$i} = chr(ord($filename{$i}) & 127);
							}
							//---------уберем сомнительные символы
							$filename = strtolower(preg_replace('/[^\w\._]/', '', $filename));
							$uplfile_name = $filename;
							$i = 1;
							// pick unused file name
							while (file_exists($this->getCurrentFsDir() . $uplfile_name)) {
								$uplfile_name = preg_replace('#(.*)(\.[a-zA-Z]+)$#', '\1_' . $i . '\2', $filename);
								$i++;
							}
							if (!@move_uploaded_file($uplfile['tmp_name'], $this->getCurrentFsDir() . $uplfile_name)) {
								$this->setError($lang->m('error_upload_failed', 'spawfm'));
							} else {
								if (strlen($this->getCurrentDirSetting('chmod_to'))) {
									// chmod uploaded file
									if (!@chmod($this->getCurrentFsDir() . $uplfile_name, $this->getCurrentDirSetting('chmod_to'))) {
										$this->setError($lang->m('error_chmod_uploaded_file', 'spawfm'));
									}
								}
							}
						}
					} else {
						$this->setError($lang->m('error_max_filesize', 'spawfm') . ' ' . round($this->getCurrentDirSetting('max_upload_filesize') / 1024, 2) . ' KB');
					}
				} else {
					$this->setError($lang->m('error_bad_filetype', 'spawfm'));
				}
			} else {
				if ($uplfile['error'] == 1 or $uplfile['error'] == 2) {
					$this->setError($lang->m('error_upload_file_too_big', 'spawfm'));
				} elseif ($uplfile['error'] == 3) {
					$this->setError($lang->m('error_upload_file_incomplete', 'spawfm'));
				} else {
					$this->setError($lang->m('error_upload_failed', 'spawfm'));
				}
			}
		}

		return $this->error() ? false : $uplfile_name;
	}

	function isSecureFile($filename)
	{
		$unsafe_ext = $this->getCurrentDirSetting('forbid_extensions');
		if (!empty($unsafe_ext)) {
			$filename = strtolower($filename);
			$arr = explode('.', $filename);
			foreach ($unsafe_ext as $ext) {
				$ext = strtolower($ext);
				if (($this->getCurrentDirSetting('forbid_extensions_strict') and in_array($ext, $arr)) or
					$ext == $arr[sizeof($arr) - 1]
				) {
					return false;
				}
			}
		}
		return true;
	}
}
